Исследование продаж игр.

data_analysis (Анализ данных)

Данные

В наличии имеются исторические данные о международных продажах игр (до 2016 г), оценки пользователей и экспертов, жанры и игровые платформы.

Задача

Провести предобработку и исследовательский анализ данных, чтобы выявить закономерности, определяющие успешность игры.

Используемые библиотеки

pandas, numpy, scipy, matplotlib, seaborn, plotly

1. Открываем файлы с данными и изучаем общую информацию.

In [1]:
#импортируем необходимые библиотеки для проведения исследования
import pandas as pd
import numpy as np
from scipy import stats as st
import warnings
In [2]:
#импортируем необходимые библиотеки для построени графиков
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import seaborn as sns
#интерактивные графики
import plotly.graph_objs as go
from plotly.offline import iplot
import plotly.figure_factory as ff
import plotly.io as pio
pio.renderers.default='notebook'
In [3]:
#считываем данные с сохранением в 'data'
data = pd.read_csv('games.csv')
#выведем 5 первых, 5 последних и 5 случайных записей 
display(data.head(5))
display(data.tail(5))
display(data.sample(5))
Name Platform Year_of_Release Genre NA_sales EU_sales JP_sales Other_sales Critic_Score User_Score Rating
0 Wii Sports Wii 2006.0 Sports 41.36 28.96 3.77 8.45 76.0 8 E
1 Super Mario Bros. NES 1985.0 Platform 29.08 3.58 6.81 0.77 NaN NaN NaN
2 Mario Kart Wii Wii 2008.0 Racing 15.68 12.76 3.79 3.29 82.0 8.3 E
3 Wii Sports Resort Wii 2009.0 Sports 15.61 10.93 3.28 2.95 80.0 8 E
4 Pokemon Red/Pokemon Blue GB 1996.0 Role-Playing 11.27 8.89 10.22 1.00 NaN NaN NaN
Name Platform Year_of_Release Genre NA_sales EU_sales JP_sales Other_sales Critic_Score User_Score Rating
16710 Samurai Warriors: Sanada Maru PS3 2016.0 Action 0.00 0.00 0.01 0.0 NaN NaN NaN
16711 LMA Manager 2007 X360 2006.0 Sports 0.00 0.01 0.00 0.0 NaN NaN NaN
16712 Haitaka no Psychedelica PSV 2016.0 Adventure 0.00 0.00 0.01 0.0 NaN NaN NaN
16713 Spirits & Spells GBA 2003.0 Platform 0.01 0.00 0.00 0.0 NaN NaN NaN
16714 Winning Post 8 2016 PSV 2016.0 Simulation 0.00 0.00 0.01 0.0 NaN NaN NaN
Name Platform Year_of_Release Genre NA_sales EU_sales JP_sales Other_sales Critic_Score User_Score Rating
2858 Fear Effect PS 1998.0 Action 0.40 0.27 0.0 0.05 NaN NaN NaN
16453 Act of Aggression PC 2015.0 Strategy 0.00 0.01 0.0 0.00 71.0 7.1 NaN
4510 Ghostbusters: The Video Game PS2 2009.0 Action 0.15 0.04 0.0 0.24 64.0 8.7 E10+
4726 Pro Pinball PS 1996.0 Misc 0.23 0.15 0.0 0.03 NaN NaN NaN
10851 NatGeo Challenge! Wild Life PS3 2010.0 Misc 0.05 0.03 0.0 0.01 NaN NaN NaN
In [4]:
data.columns
#В названии столбцов присутствуют буквы верхних и нижних регистров, лишних пробелов нет 
Out[4]:
Index(['Name', 'Platform', 'Year_of_Release', 'Genre', 'NA_sales', 'EU_sales',
       'JP_sales', 'Other_sales', 'Critic_Score', 'User_Score', 'Rating'],
      dtype='object')
In [5]:
data.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 16715 entries, 0 to 16714
Data columns (total 11 columns):
Name               16713 non-null object
Platform           16715 non-null object
Year_of_Release    16446 non-null float64
Genre              16713 non-null object
NA_sales           16715 non-null float64
EU_sales           16715 non-null float64
JP_sales           16715 non-null float64
Other_sales        16715 non-null float64
Critic_Score       8137 non-null float64
User_Score         10014 non-null object
Rating             9949 non-null object
dtypes: float64(6), object(5)
memory usage: 1.4+ MB

Вывод

Всего в таблице 11 столбцов.

У шести столбцов тип данных - float64, у пяти - object.

Общее количество записей: 16715.

В 6 столбцах имеются пропуски в данных: Name, Year_of_Release, Genre, Critic_Score, User_Score, Rating.

2. Подготовка данных

1) Замена названий столбцов.

In [6]:
#приведем к нижнему регистру
data.columns = data.columns.str.lower()
data.head()
Out[6]:
name platform year_of_release genre na_sales eu_sales jp_sales other_sales critic_score user_score rating
0 Wii Sports Wii 2006.0 Sports 41.36 28.96 3.77 8.45 76.0 8 E
1 Super Mario Bros. NES 1985.0 Platform 29.08 3.58 6.81 0.77 NaN NaN NaN
2 Mario Kart Wii Wii 2008.0 Racing 15.68 12.76 3.79 3.29 82.0 8.3 E
3 Wii Sports Resort Wii 2009.0 Sports 15.61 10.93 3.28 2.95 80.0 8 E
4 Pokemon Red/Pokemon Blue GB 1996.0 Role-Playing 11.27 8.89 10.22 1.00 NaN NaN NaN

2) Обработка пропусков

In [7]:
#вычислим количество пропусков в столбцах
print(data.isnull().sum())
name                  2
platform              0
year_of_release     269
genre                 2
na_sales              0
eu_sales              0
jp_sales              0
other_sales           0
critic_score       8578
user_score         6701
rating             6766
dtype: int64

Разберемся со столбцами где мало пропусков.

1. Рассмотрим столбцы name и genre

In [8]:
data[data['name'].isnull() & data['genre'].isnull()]
Out[8]:
name platform year_of_release genre na_sales eu_sales jp_sales other_sales critic_score user_score rating
659 NaN GEN 1993.0 NaN 1.78 0.53 0.00 0.08 NaN NaN NaN
14244 NaN GEN 1993.0 NaN 0.00 0.00 0.03 0.00 NaN NaN NaN
In [9]:
#пропуски присутствуют одновременно в 5 столбцах, поэтому лучше удалить их полностью
data.dropna(subset = ['name', 'genre'], inplace = True)
#data=data.fillna({'name': 'unknow', 'genre':'unknow'})
In [10]:
print(data.isnull().sum())
name                  0
platform              0
year_of_release     269
genre                 0
na_sales              0
eu_sales              0
jp_sales              0
other_sales           0
critic_score       8576
user_score         6699
rating             6764
dtype: int64

2. Рассмотрим столбец year_of_release

Возможно, что игры выходят на нескольких платформах одновременно и тогда можно восстановить год релиза по другим платформам.

In [11]:
#Запишем названия игр с пропусков годе релиза в список "Name"
Name = data[data['year_of_release'].isnull()]['name']
#Удалим дублирующие элементы
Name=Name.drop_duplicates()
display(len(Name))
#проверим есть ли игры с такими же названиями на других платформах
data_year = data.query('name in @Name')
len(data_year)
232
Out[11]:
473
In [12]:
#из этого списка нужны игры. которые вышли минимум на двух платформах
name_more_two = data_year.pivot_table(index='name', values='platform', aggfunc = 'count').query('platform > 1')
len(name_more_two)
Out[12]:
109
In [13]:
#~47% пропусков имели релизы на других платформах, найдем эти игры и посчитаем для них медианный год выхода
data_year_more_two = data.query('name in @name_more_two.index').\
                                            pivot_table(index='name', values = 'year_of_release', aggfunc= 'median')
#Осталось удалить строки с пропусками, 
#т.к. они говорят о том, что для всех платформ, на которых выходила игра, отсутствует запись о годе релиза.
data_year_more_two = data_year_more_two.dropna()
print(len(data_year_more_two))

data_year_more_two['year_of_release'].value_counts()
#в колонках с годами присутствуют дробных значения, от них мы избавимся в дальнейшем, когда будем приводить к целому типу
#так же отметим, что таких элементов мало, всего 3 игры
99
Out[13]:
2006.0    13
2002.0    12
2011.0    11
2010.0    11
2008.0    10
2003.0     9
2005.0     5
2007.0     4
2009.0     4
2013.0     3
2012.0     3
2001.0     3
2004.0     3
1999.0     2
2002.5     2
2000.0     1
2013.5     1
2001.5     1
2005.5     1
Name: year_of_release, dtype: int64
In [14]:
data_year_more_two['year_of_release'][15:30]
#сразу отметим, для спортивных игр (типа "FIFA Soccer 2004") релиз происходи на год раньше указанной даты в названии (2003)
Out[14]:
name
Dead Space 3                              2013.0
Def Jam: Fight for NY                     2004.0
Dinotopia: The Sunstone Odyssey           2003.0
Disney's Chicken Little: Ace In Action    2006.0
FIFA Soccer 2004                          2003.0
Final Fantasy XI                          2006.0
Freaky Flyers                             2003.0
GRID                                      2008.0
Get Fit with Mel B                        2010.0
Godzilla: Destroy All Monsters Melee      2002.0
Gun                                       2005.0
Happy Feet Two                            2011.0
Harvest Moon: The Tale of Two Towns       2010.0
Hitman 2: Silent Assassin                 2002.5
Inversion                                 2012.0
Name: year_of_release, dtype: float64
In [15]:
#проведем замену пустых значений по полученному словарю
#для проверки
display(data.query('name == "LEGO Harry Potter: Years 5-7"'))
display(data.query('name == "FIFA Soccer 2004"'))
display(data.query('name == "Hitman 2: Silent Assassin"'))
name platform year_of_release genre na_sales eu_sales jp_sales other_sales critic_score user_score rating
1609 LEGO Harry Potter: Years 5-7 Wii NaN Action 0.69 0.42 0.0 0.12 76.0 7.8 E10+
2132 LEGO Harry Potter: Years 5-7 X360 NaN Action 0.51 0.37 0.0 0.09 77.0 7.9 E10+
2273 LEGO Harry Potter: Years 5-7 PS3 NaN Action 0.36 0.41 0.0 0.15 76.0 8.3 E10+
3081 LEGO Harry Potter: Years 5-7 DS NaN Action 0.34 0.25 0.0 0.07 69.0 tbd E10+
4818 LEGO Harry Potter: Years 5-7 3DS NaN Action 0.18 0.19 0.0 0.03 71.0 6.5 E10+
6476 LEGO Harry Potter: Years 5-7 PSP NaN Action 0.10 0.10 0.0 0.06 NaN tbd E10+
7210 LEGO Harry Potter: Years 5-7 PC NaN Action 0.05 0.14 0.0 0.03 80.0 8.5 E10+
8059 LEGO Harry Potter: Years 5-7 PSV 2012.0 Action 0.07 0.07 0.0 0.03 64.0 6.8 E10+
name platform year_of_release genre na_sales eu_sales jp_sales other_sales critic_score user_score rating
377 FIFA Soccer 2004 PS2 NaN Sports 0.59 2.36 0.04 0.51 84.0 6.4 E
2606 FIFA Soccer 2004 XB 2003.0 Sports 0.24 0.49 0.00 0.05 82.0 8.2 E
12029 FIFA Soccer 2004 GC 2003.0 Sports 0.05 0.01 0.00 0.00 83.0 6.2 E
13086 FIFA Soccer 2004 GBA 2003.0 Sports 0.04 0.01 0.00 0.00 82.0 7.9 E
name platform year_of_release genre na_sales eu_sales jp_sales other_sales critic_score user_score rating
483 Hitman 2: Silent Assassin PS2 2002.0 Action 1.36 1.15 0.04 0.41 85.0 7.8 M
1699 Hitman 2: Silent Assassin XB NaN Action 0.76 0.38 0.00 0.05 84.0 8 M
9493 Hitman 2: Silent Assassin GC 2003.0 Action 0.10 0.03 0.00 0.00 83.0 5.5 M

Заметим, что одинаковым названиям игр, соответствуют одинаковые рейтинги ESRB.

In [16]:
for row in data_year_more_two.index:
    data.loc[((data['name'] == row) & (data['year_of_release'].isnull())), 'year_of_release'] =\
                                                                                data_year_more_two['year_of_release'][row]
    #print(data_year_more_two['year_of_release'][row])
In [17]:
display(data.query('name == "LEGO Harry Potter: Years 5-7"'))
display(data.query('name == "FIFA Soccer 2004"'))
display(data.query('name == "Hitman 2: Silent Assassin"'))
name platform year_of_release genre na_sales eu_sales jp_sales other_sales critic_score user_score rating
1609 LEGO Harry Potter: Years 5-7 Wii 2012.0 Action 0.69 0.42 0.0 0.12 76.0 7.8 E10+
2132 LEGO Harry Potter: Years 5-7 X360 2012.0 Action 0.51 0.37 0.0 0.09 77.0 7.9 E10+
2273 LEGO Harry Potter: Years 5-7 PS3 2012.0 Action 0.36 0.41 0.0 0.15 76.0 8.3 E10+
3081 LEGO Harry Potter: Years 5-7 DS 2012.0 Action 0.34 0.25 0.0 0.07 69.0 tbd E10+
4818 LEGO Harry Potter: Years 5-7 3DS 2012.0 Action 0.18 0.19 0.0 0.03 71.0 6.5 E10+
6476 LEGO Harry Potter: Years 5-7 PSP 2012.0 Action 0.10 0.10 0.0 0.06 NaN tbd E10+
7210 LEGO Harry Potter: Years 5-7 PC 2012.0 Action 0.05 0.14 0.0 0.03 80.0 8.5 E10+
8059 LEGO Harry Potter: Years 5-7 PSV 2012.0 Action 0.07 0.07 0.0 0.03 64.0 6.8 E10+
name platform year_of_release genre na_sales eu_sales jp_sales other_sales critic_score user_score rating
377 FIFA Soccer 2004 PS2 2003.0 Sports 0.59 2.36 0.04 0.51 84.0 6.4 E
2606 FIFA Soccer 2004 XB 2003.0 Sports 0.24 0.49 0.00 0.05 82.0 8.2 E
12029 FIFA Soccer 2004 GC 2003.0 Sports 0.05 0.01 0.00 0.00 83.0 6.2 E
13086 FIFA Soccer 2004 GBA 2003.0 Sports 0.04 0.01 0.00 0.00 82.0 7.9 E
name platform year_of_release genre na_sales eu_sales jp_sales other_sales critic_score user_score rating
483 Hitman 2: Silent Assassin PS2 2002.0 Action 1.36 1.15 0.04 0.41 85.0 7.8 M
1699 Hitman 2: Silent Assassin XB 2002.5 Action 0.76 0.38 0.00 0.05 84.0 8 M
9493 Hitman 2: Silent Assassin GC 2003.0 Action 0.10 0.03 0.00 0.00 83.0 5.5 M
In [18]:
data.isnull().sum()/len(data)*100
Out[18]:
name                0.000000
platform            0.000000
year_of_release     0.873571
genre               0.000000
na_sales            0.000000
eu_sales            0.000000
jp_sales            0.000000
other_sales         0.000000
critic_score       51.313349
user_score         40.082570
rating             40.471489
dtype: float64
In [19]:
#Остальные года трудно восстановить на основе имеющихся данных. Если сильно надо, можно посмотреть даты релизов в интернете 
#по каждой игре. Однако, процент пропусков незначительный меньше одного процента, поэтому удалим данные с пропусками.
data.dropna(subset = ['year_of_release'], inplace = True)
data.isnull().sum()/len(data)*100
Out[19]:
name                0.000000
platform            0.000000
year_of_release     0.000000
genre               0.000000
na_sales            0.000000
eu_sales            0.000000
jp_sales            0.000000
other_sales         0.000000
critic_score       51.258526
user_score         40.037424
rating             40.435806
dtype: float64

3. Рассмотрим столбец rating

т.к. ESRB была основана в 1994 году, проверим оценивала ли данная организация игры, выпущенные годами ранее

In [20]:
data.query('rating == rating and year_of_release < 1994')
Out[20]:
name platform year_of_release genre na_sales eu_sales jp_sales other_sales critic_score user_score rating
2612 The 7th Guest PC 1992.0 Adventure 0.02 0.77 0.0 0.00 NaN NaN T
14470 Alter Ego PC 1985.0 Simulation 0.00 0.03 0.0 0.01 59.0 5.8 T
14610 Doom PC 1992.0 Shooter 0.02 0.00 0.0 0.00 85.0 8.2 M
14621 SimCity PC 1988.0 Simulation 0.00 0.02 0.0 0.01 64.0 2.2 E10+
In [21]:
ax = data.query('rating != rating')['year_of_release'].plot(kind='hist', grid=True, \
                                                            title='Год релиза игры, с отсутсвующим рейтингом')
ax.set_xlabel('year')
plt.show()

Получается, что организация проверяет игры, которые были выпущены до ее существования. И организация выставляет рейтинг не всем играм.

Ранее мы заметили, что одинаковым названиям игр, соответствуют одинаковые рейтинги ESRB. Проверим, что у игры без рейтинга, так же нет рейтинга на другой платформе.

In [22]:
#data.query('rating != rating')
#Запишем названия игр с пропуском рейтинга в список "Name"
Name = data[data['rating'].isnull()]['name']
Name=Name.drop_duplicates()
display(len(Name))

#проверим есть ли игры с такими же названиями на других платформах
name_more_two = data.query('name in @Name').\
                                    pivot_table(index='name', values='platform', aggfunc = 'count').query('platform > 1')
display(len(name_more_two))

display(data.query('name == "Banjo-Kazooie"'))
5787
939
name platform year_of_release genre na_sales eu_sales jp_sales other_sales critic_score user_score rating
345 Banjo-Kazooie N64 1998.0 Platform 1.87 1.13 0.55 0.1 NaN NaN NaN
16311 Banjo-Kazooie X360 2008.0 Platform 0.00 0.01 0.00 0.0 77.0 8.2 E

Получили, что из 5787 игр 939 есть на других платформах

In [23]:
data_rating_more_two = data.query('name in @name_more_two.index and rating == rating').\
                                            pivot_table(index='name', values = 'rating', aggfunc= 'first')
print(len(data_rating_more_two))
#для 359 игр, с пропущенным рейтингом, удается определить рейтинг по другим платформам
359
In [24]:
#проведем замену
for row in data_rating_more_two.index:
    data.loc[((data['name'] == row) & (data['rating'].isnull())), 'rating'] =\
                                                                                data_rating_more_two['rating'][row]
display(data.query('name == "Banjo-Kazooie"'))
data.isnull().sum()/len(data)*100
name platform year_of_release genre na_sales eu_sales jp_sales other_sales critic_score user_score rating
345 Banjo-Kazooie N64 1998.0 Platform 1.87 1.13 0.55 0.1 NaN NaN E
16311 Banjo-Kazooie X360 2008.0 Platform 0.00 0.01 0.00 0.0 77.0 8.2 E
Out[24]:
name                0.000000
platform            0.000000
year_of_release     0.000000
genre               0.000000
na_sales            0.000000
eu_sales            0.000000
jp_sales            0.000000
other_sales         0.000000
critic_score       51.258526
user_score         40.037424
rating             37.798032
dtype: float64

Данный подход позволил избавиться от ~2.7% пропусков в столбце. По жанру игр тоже не получается провести адекватную замену, поэтому заменим оставшиеся пропуски на значение - "unknow"

In [25]:
#проведем замену 
data.loc[data['rating'].isna(), 'rating'] = 'unknow'
display(data.head())
display(data.isnull().sum())
name platform year_of_release genre na_sales eu_sales jp_sales other_sales critic_score user_score rating
0 Wii Sports Wii 2006.0 Sports 41.36 28.96 3.77 8.45 76.0 8 E
1 Super Mario Bros. NES 1985.0 Platform 29.08 3.58 6.81 0.77 NaN NaN unknow
2 Mario Kart Wii Wii 2008.0 Racing 15.68 12.76 3.79 3.29 82.0 8.3 E
3 Wii Sports Resort Wii 2009.0 Sports 15.61 10.93 3.28 2.95 80.0 8 E
4 Pokemon Red/Pokemon Blue GB 1996.0 Role-Playing 11.27 8.89 10.22 1.00 NaN NaN unknow
name                  0
platform              0
year_of_release       0
genre                 0
na_sales              0
eu_sales              0
jp_sales              0
other_sales           0
critic_score       8492
user_score         6633
rating                0
dtype: int64

4. Рассмотрим столбец critic_score

На примере ниже можно убедиться, что для одной и тойже игры у разных платформ различные рейтинги, как у критиков так и пользователей.

In [26]:
#создадим функцию, которая для столбца column строит гистограмму по жанрам
#параметр x_lable - подпись горизонтальной оси 
def hist_genre(column, x_lable):
    try:
        fig,  ax  =  plt.subplots(nrows = 3, ncols=4 ,  figsize= (15 ,  8)) 
        
        i = 0
        for name, group_data in data.groupby('genre'):
            
            ax_cycle = ax[int((i)/4)][(i)%4]
        
            group_data[group_data[column].isnull() == False].plot(kind='hist', y=column, ax=ax_cycle,\
                                          title = name, label='Оценка', alpha=0.65, grid=True)
            
            ax_cycle.set_xlabel(x_lable)
            i += 1
    
        fig.tight_layout()
        plt.show()
    except:
        print("ERROR in hist_genre!!!")
In [27]:
display(data.query('name == "LEGO Harry Potter: Years 5-7"'))

#посчитаем коэффициент корреляции
data[data['critic_score'].isna() == False]['critic_score'].\
                                            corr(data[(data['user_score'].isna() == False) &
                                                     (data['user_score'] != 'tbd')]['user_score'].astype('float64'))
name platform year_of_release genre na_sales eu_sales jp_sales other_sales critic_score user_score rating
1609 LEGO Harry Potter: Years 5-7 Wii 2012.0 Action 0.69 0.42 0.0 0.12 76.0 7.8 E10+
2132 LEGO Harry Potter: Years 5-7 X360 2012.0 Action 0.51 0.37 0.0 0.09 77.0 7.9 E10+
2273 LEGO Harry Potter: Years 5-7 PS3 2012.0 Action 0.36 0.41 0.0 0.15 76.0 8.3 E10+
3081 LEGO Harry Potter: Years 5-7 DS 2012.0 Action 0.34 0.25 0.0 0.07 69.0 tbd E10+
4818 LEGO Harry Potter: Years 5-7 3DS 2012.0 Action 0.18 0.19 0.0 0.03 71.0 6.5 E10+
6476 LEGO Harry Potter: Years 5-7 PSP 2012.0 Action 0.10 0.10 0.0 0.06 NaN tbd E10+
7210 LEGO Harry Potter: Years 5-7 PC 2012.0 Action 0.05 0.14 0.0 0.03 80.0 8.5 E10+
8059 LEGO Harry Potter: Years 5-7 PSV 2012.0 Action 0.07 0.07 0.0 0.03 64.0 6.8 E10+
Out[27]:
0.5800874343029765

Присутствует достаточно сильная прямая корреляция между оценками критиков и пользователей (в данных без пропусков), но проводить замену на основе рейтинга пользователей неверно, т.к. случается ситуация, что критики высоко оценивают, а пользователи нет, как и наоборот.

In [28]:
hist_genre('critic_score', 'Оценки критиков')

Проводить замену медианными значениями по жанрам так же будет неправильно, поэтому будем предпологать, что данных просто нет, пропуски можно пометить отрицательным значением: -1. Нулем заменять нельзя, т.к. оценка игры, теоретически, может быть нулевая. Аналогичную замену сделаем в столбце с рейтингом пользователей. Однако, чтобы не вводить сильную путаниц оставим пропуски как есть.

In [29]:
#data=data.fillna({'critic_score': -1, 'user_score': -1})

display(data.head())
name platform year_of_release genre na_sales eu_sales jp_sales other_sales critic_score user_score rating
0 Wii Sports Wii 2006.0 Sports 41.36 28.96 3.77 8.45 76.0 8 E
1 Super Mario Bros. NES 1985.0 Platform 29.08 3.58 6.81 0.77 NaN NaN unknow
2 Mario Kart Wii Wii 2008.0 Racing 15.68 12.76 3.79 3.29 82.0 8.3 E
3 Wii Sports Resort Wii 2009.0 Sports 15.61 10.93 3.28 2.95 80.0 8 E
4 Pokemon Red/Pokemon Blue GB 1996.0 Role-Playing 11.27 8.89 10.22 1.00 NaN NaN unknow
In [30]:
data.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 16567 entries, 0 to 16714
Data columns (total 11 columns):
name               16567 non-null object
platform           16567 non-null object
year_of_release    16567 non-null float64
genre              16567 non-null object
na_sales           16567 non-null float64
eu_sales           16567 non-null float64
jp_sales           16567 non-null float64
other_sales        16567 non-null float64
critic_score       8075 non-null float64
user_score         9934 non-null object
rating             16567 non-null object
dtypes: float64(6), object(5)
memory usage: 1.5+ MB
In [31]:
data.query('user_score == "tbd"').head()
Out[31]:
name platform year_of_release genre na_sales eu_sales jp_sales other_sales critic_score user_score rating
119 Zumba Fitness Wii 2010.0 Sports 3.45 2.59 0.0 0.66 NaN tbd E
301 Namco Museum: 50th Anniversary PS2 2005.0 Misc 2.08 1.35 0.0 0.54 61.0 tbd E10+
520 Zumba Fitness 2 Wii 2011.0 Sports 1.51 1.03 0.0 0.27 NaN tbd T
645 uDraw Studio Wii 2010.0 Misc 1.65 0.57 0.0 0.20 71.0 tbd E
718 Just Dance Kids Wii 2010.0 Misc 1.52 0.54 0.0 0.18 NaN tbd E

Осталось разобраться с аббревиатурой "tbd" (to be determined) - "подлежит определению". Необходимо, уточнить как происходит сбор данных. Мы предположим, что оценка пользователей начинает отображаться после голосования определенного числа пользователей (условно 100 пользователей), т.е. на данный момент данных нет, но они могут вскоре поступит (например сейчас оценку поставили 80 пользователей). Их также можно пометить отрицательным значением: "-2" и делать фильтрацию, но мы оставим пропуски ка есть.

In [32]:
#data.loc[data['user_score'] == "tbd", 'user_score'] = -2
data.loc[data['user_score'] == "tbd", 'user_score'] = np.NaN

display(data.query('name == "Zumba Fitness"'))
name platform year_of_release genre na_sales eu_sales jp_sales other_sales critic_score user_score rating
119 Zumba Fitness Wii 2010.0 Sports 3.45 2.59 0.0 0.66 NaN NaN E
669 Zumba Fitness X360 2010.0 Sports 1.74 0.45 0.0 0.18 42.0 5.5 E
3516 Zumba Fitness PS3 2010.0 Sports 0.28 0.21 0.0 0.08 NaN 3.8 E

4) Преобразование данных к нужным типам.

В целом с типами данных в таблицах все неплохо, за исключением столбца с оценками пользователей. Поэтому преобразуем user_score - с типом object к типу float64. И для удобства преобразуем год релиза year_of_release к целому типу int64.

In [33]:
#для проверки
display(data.query('name == "Hitman 2: Silent Assassin"'))
name platform year_of_release genre na_sales eu_sales jp_sales other_sales critic_score user_score rating
483 Hitman 2: Silent Assassin PS2 2002.0 Action 1.36 1.15 0.04 0.41 85.0 7.8 M
1699 Hitman 2: Silent Assassin XB 2002.5 Action 0.76 0.38 0.00 0.05 84.0 8 M
9493 Hitman 2: Silent Assassin GC 2003.0 Action 0.10 0.03 0.00 0.00 83.0 5.5 M
In [34]:
data['user_score'] = data['user_score'].astype('float64')
data['year_of_release'] = data['year_of_release'].astype('int64') 
In [35]:
#для проверки
display(data.query('name == "Hitman 2: Silent Assassin"'))
name platform year_of_release genre na_sales eu_sales jp_sales other_sales critic_score user_score rating
483 Hitman 2: Silent Assassin PS2 2002 Action 1.36 1.15 0.04 0.41 85.0 7.8 M
1699 Hitman 2: Silent Assassin XB 2002 Action 0.76 0.38 0.00 0.05 84.0 8.0 M
9493 Hitman 2: Silent Assassin GC 2003 Action 0.10 0.03 0.00 0.00 83.0 5.5 M
In [36]:
data.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 16567 entries, 0 to 16714
Data columns (total 11 columns):
name               16567 non-null object
platform           16567 non-null object
year_of_release    16567 non-null int64
genre              16567 non-null object
na_sales           16567 non-null float64
eu_sales           16567 non-null float64
jp_sales           16567 non-null float64
other_sales        16567 non-null float64
critic_score       8075 non-null float64
user_score         7540 non-null float64
rating             16567 non-null object
dtypes: float64(6), int64(1), object(4)
memory usage: 1.5+ MB

Замена типа данных прошла успешно. Отметим, что в year_of_release дробная часть отбросилась в ходе преобразования.

5) Преобразование таблицы.

In [37]:
display(data['rating'].value_counts())
unknow    6262
E         4119
T         3063
M         1644
E10+      1462
EC          10
K-A          4
RP           2
AO           1
Name: rating, dtype: int64

В столбце с рейтингом ESRB, есть 4 значения "K-A". Данная аббревиатура является устаревшей для "Е", поэтому произведем соответствующую замену.

In [38]:
data.loc[data['rating'] == 'K-A', 'rating'] = "E"
display(data['rating'].value_counts())
unknow    6262
E         4123
T         3063
M         1644
E10+      1462
EC          10
RP           2
AO           1
Name: rating, dtype: int64

Посчитаем суммарные продажи во всех регионах и запишим их в отдельный столбец all_sales

In [39]:
data['all_sales'] = data['na_sales']+data['eu_sales']+data['jp_sales']+data['other_sales']
data.head()
Out[39]:
name platform year_of_release genre na_sales eu_sales jp_sales other_sales critic_score user_score rating all_sales
0 Wii Sports Wii 2006 Sports 41.36 28.96 3.77 8.45 76.0 8.0 E 82.54
1 Super Mario Bros. NES 1985 Platform 29.08 3.58 6.81 0.77 NaN NaN unknow 40.24
2 Mario Kart Wii Wii 2008 Racing 15.68 12.76 3.79 3.29 82.0 8.3 E 35.52
3 Wii Sports Resort Wii 2009 Sports 15.61 10.93 3.28 2.95 80.0 8.0 E 32.77
4 Pokemon Red/Pokemon Blue GB 1996 Role-Playing 11.27 8.89 10.22 1.00 NaN NaN unknow 31.38
In [40]:
#найдем количество дублирующих значений в датасете
print(data.duplicated().sum())
0

Вывод

В итоге мы обнаружили все пропуски и произвели их замену, отметили встречающиеся аномалии. Где необходимо изменили тип данных. Проверили на наличие дубликатов. Добавили столбец суммарных продаж во всех регионах Преобразованнный DataFrame готов к последующему анализу.

3. Исследовательский анализ данных.

In [41]:
#Для первого случая найдем уникальные игры
data_name = data.pivot_table(index='name', values='year_of_release', aggfunc=['first'])
data_name.columns = ['year']

data_name = data_name['year'].value_counts().sort_index()
In [42]:
#Построим соответствующий график
trace0 = go.Scatter(
            x=data.groupby('year_of_release')['year_of_release'].count().index,
            y=data.groupby('year_of_release')['year_of_release'].count(),
            mode='lines+markers',
            name='Игры на всех платформах'
)

trace1 = go.Scatter(
            x=data_name.index,
            y=data_name,
            mode='lines+markers',
            name='Уникальные игры'
)

fig = go.Figure(data=[trace0, trace1],\
               layout = {'title': 'Количество выпускаемых игр в разные годы', \
                         'xaxis_title' : 'Годы',\
                         'yaxis_title' : 'Количество игр'})
fig.show()

Вывод

После 1993 года наблюдается рост в количестве выпускаемых игры. Пик достигается в 2008 году, затем идет спад (скорее всего связанный с экономически кризисом) и, начиная с 2013г включительно, ежегодно выпускается приблизительно равное количество игр. Также стоит отметить, что производители компьютерных игр начинают практиковать одновременный выход игр на разных платформах с 2002г.

Получается, что для планирования кампании на 2017-й год, наиболее важными оказываются данные с 2013 по 2016гг.

In [43]:
#Вычислим суммарные продажи по платформам.
data_platform_sales = data.pivot_table(index='platform', values='all_sales', aggfunc='sum')
data_platform_sales=data_platform_sales.sort_values(by='all_sales', ascending=False)

#Для выбора платформ с наибольшими суммарными продажами построим круговую диаграмму
labels = data_platform_sales['all_sales'].index
values = data_platform_sales['all_sales']

fig = go.Figure(data=[go.Pie(labels=labels, values=values, hole=0.25)], \
                layout = {'title': 'Суммарные продажи игр по платформам за все время'})
fig.show()
In [44]:
ax = data_platform_sales.plot(kind='bar', grid=True, figsize=(15,6))

ax.set_xlabel('Платформа')  
ax.set_ylabel('МЛН. $') 
ax.set_title("Суммарные продажи игр по платформам за все время") 
ax.label='g1'
plt.show()

Для дальнейшего анализа выберем платформы у которых процент доли суммарных продаж выше 8%: PS2, X360, PS3, Wii, DS, PS.

In [45]:
#сохраним названия платформ
name_platform_sales_top = data_platform_sales.head(6).index.values
print(name_platform_sales_top)

#В данных имеется аномалия для платформы DS (сама платформа вышла в 2004 году).
data.query('platform == "DS" and year_of_release < 1994')
['PS2' 'X360' 'PS3' 'Wii' 'DS' 'PS']
Out[45]:
name platform year_of_release genre na_sales eu_sales jp_sales other_sales critic_score user_score rating all_sales
15957 Strongest Tokyo University Shogi DS DS 1985 Action 0.0 0.0 0.02 0.0 NaN NaN unknow 0.02
In [46]:
#Эту игру 1985 перевыпустили для данной платформы в 2007 году (нашел в интернете), поэтому проведем замену соответсвующую
data.loc[data['name'] == 'Strongest Tokyo University Shogi DS', 'year_of_release'] = 2007
data[data['name'] == 'Strongest Tokyo University Shogi DS']
Out[46]:
name platform year_of_release genre na_sales eu_sales jp_sales other_sales critic_score user_score rating all_sales
15957 Strongest Tokyo University Shogi DS DS 2007 Action 0.0 0.0 0.02 0.0 NaN NaN unknow 0.02
In [47]:
#Выберем нужный срез, сгрупппируем данные и построем графики

#Для визуализации
trace = []

for i in name_platform_sales_top:
    
    data_name_platform = data.query('platform == @i').\
                                                pivot_table(index='year_of_release', values='all_sales', aggfunc='sum')
    data_name_platform.columns = ['sales']
    #display(data_name_platform)
    
    trace_i = go.Scatter(
        x=data_name_platform.index,
        y=data_name_platform['sales'],
        mode='lines+markers',
        name=i
    )
    trace.append(trace_i)
    
fig = go.Figure(data=trace,layout = {'title': 'Суммарные продажи для разных платформ по годам',\
                                         'xaxis_title' : 'Годы',\
                                         'yaxis_title' : 'млн. $'})
fig.show()

Из графика идно, что к 2016 году прекратились продажи для платформ PS, PS2, DS. А у оставшихся к 2016 году сильно упали суммарные продажи. Также из это графика следует, что с 2004 года чаще стали появляться новые платформы. Причем пик суммарных продаж игр на новой платформе наступает через 4-5 лет послее выхода платформы, а затем 6-8 лет суммарные продажи падают. Возможно, что падение продаж на старой платформе связано с выходом игр на новых платформах (пик продаж примерно приходится на годы появления новой платформы).

Приведем расчет среднего значения.

In [48]:
#Всего есть 31 платформа
data['platform'].unique()
Out[48]:
array(['Wii', 'NES', 'GB', 'DS', 'X360', 'PS3', 'PS2', 'SNES', 'GBA',
       'PS4', '3DS', 'N64', 'PS', 'XB', 'PC', '2600', 'PSP', 'XOne',
       'WiiU', 'GC', 'GEN', 'DC', 'PSV', 'SAT', 'SCD', 'WS', 'NG', 'TG16',
       '3DO', 'GG', 'PCFX'], dtype=object)
In [49]:
platform_life=[]

for name in data['platform'].unique():
    data_platform_name = data.query('platform == @name')
    
    first_year = data_platform_name['year_of_release'].sort_values().head(1).values
    last_year = data_platform_name['year_of_release'].sort_values().tail(1).values
    dist = (last_year - first_year + 1)[0]
    
    platform_life.append(dist)

platform_life_df = pd.DataFrame()
platform_life_df['year_life']= platform_life
platform_life_df['platform'] =  data['platform'].unique()

fig = go.Figure(data=go.Bar(
            x=platform_life_df['platform'],
            y=platform_life_df['year_life'],
            ), layout = {'title': 'Время существование дяя каждой игровой платформы', 'xaxis_title' : 'Платформы',\
                         'yaxis_title' : 'Годы'})
                
fig.show()
In [50]:
platform_life_df.boxplot('year_life', figsize=(6,5))
plt.show()

Такаяя платформа как PC cуществует уже необычно долго, 32 года, что в наших данных является выбросом (boxplot выше это подтверждает). Так же для расчета среднего времени существования платформы нужно исключить недавнопоявившиеся платформы, которые продолжают существовать на 2016 год. Исключать все платформы в 2016, на которых выходят игры, будет неверно, т.к. такие платформы как PS3 и X360 уже прекращают свое существование, это следует из графиков суммарных продаж.

In [51]:
name_new_platform = data.query('year_of_release == 2016')['platform'].unique()

display(platform_life_df.query('platform in @ name_new_platform'))

#Вручную создадим список исключающих платформ, 
#здесь будет выброс - PC и молодые платформы, которые существовали меньше 7 лет
name_new_platform = ['PC', 'PS4', 'XOne', 'WiiU', 'PSV']
name_new_platform
year_life platform
0 11 Wii
4 12 X360
5 12 PS3
9 4 PS4
10 17 3DS
14 32 PC
17 4 XOne
18 5 WiiU
22 6 PSV
Out[51]:
['PC', 'PS4', 'XOne', 'WiiU', 'PSV']
In [52]:
#исключим аномальные и молодые платформы из рассмотрения и посчитаем статистические характеристики
platform_life_df.query('platform not in @ name_new_platform').reset_index(drop=True).describe()
Out[52]:
year_life
count 26.00000
mean 8.50000
std 5.06162
min 1.00000
25% 4.25000
50% 9.50000
75% 12.00000
max 20.00000

Вывод

Таким образом, среднее значение продолжительности существования платформы составляет 8.5 лет, медианное - 9,5 лет. Выводы, полученные по графикам, были слегка завышены.

In [53]:
#построим ленточную диаграмму (Диаграмму Ганта)

#специальный датафрейм для построения ленточной диаграммы
for_gunt = pd.DataFrame(columns=['Task', "Start", 'Finish'])

#переменная итератор
temp = 0
for i in name_platform_sales_top:
    
    data_name_platform = data.query('platform == @i').\
                                            pivot_table(index='year_of_release', values='all_sales', aggfunc='sum') 
    #display(data_name_platform.index)
    for_gunt.loc[temp] = [i, data_name_platform.index[0], data_name_platform.index[-1]]
    temp += 1
    
fig = ff.create_gantt(for_gunt, show_colorbar=True, bar_width=0.2, showgrid_x=True, showgrid_y=True,\
                      title='Период продаж игр для разных платформ')
fig.show()

Выводы

Мы получили, что время от выхода новой платформы до прекращения продаж игр на ней составляет примерно 10-12 лет.

На основе динамики линейки платформ одного производителя PS, PS2, PS3 можно сказать, что новая платформа выход каждые 5-6 лет. Это совпадает с высказаным ранее предположением о том, что пик продаж примерно приходится на дату появления новой платформы.

Расчет среднего времени выхода новой плотформы у PlayStation и Xbox

In [54]:
data_platform_ps = ['PS', 'PS2', 'PS3', 'PS4'] 

data_platform_xb = ['XB', 'X360', 'XOne']
#'PSV', 'PSP' - это портативные платформы, я их сюда не включил, рассмотрев только стационарные

for_gunt_ps = pd.DataFrame(columns=['Task', "Start", 'Finish'])
for_gunt_xb = pd.DataFrame(columns=['Task', "Start", 'Finish'])

#PS
temp = 0
for i in data_platform_ps:
    
    data_name_platform = data.query('platform == @i').\
                                            pivot_table(index='year_of_release', values='all_sales', aggfunc='sum') 

    for_gunt_ps.loc[temp] = [i, data_name_platform.index[0], data_name_platform.index[-1]]
    temp += 1
    


for_gunt_ps = for_gunt_ps.sort_values(by='Start')
display(for_gunt_ps)

#Xbox
temp = 0
for i in data_platform_xb:
    
    data_name_platform = data.query('platform == @i').\
                                            pivot_table(index='year_of_release', values='all_sales', aggfunc='sum') 

    for_gunt_xb.loc[temp] = [i, data_name_platform.index[0], data_name_platform.index[-1]]
    temp += 1
    


for_gunt_xb = for_gunt_xb.sort_values(by='Start')
display(for_gunt_xb)
Task Start Finish
0 PS 1994 2003
1 PS2 2000 2011
2 PS3 2005 2016
3 PS4 2013 2016
Task Start Finish
0 XB 2000 2008
1 X360 2005 2016
2 XOne 2013 2016
In [55]:
diff = 0.0

for year in for_gunt_ps['Start']:
    if(year == 1994):
        first = year;
    else:
        diff = diff+(year-first)
        first = year

print('Cреднее время появления для платформ линейки PS: ', diff/(len(for_gunt_ps)-1)) 


diff = 0.0

for year in for_gunt_xb['Start']:
    if(year == 2000):
        first = year;
    else:
        diff = diff+(year-first)
        first = year


print('Cреднее время появления для платформ линейки Xbox: ', diff/(len(for_gunt_xb)-1))
Cреднее время появления для платформ линейки PS:  6.333333333333333
Cреднее время появления для платформ линейки Xbox:  6.5

Вывод

Среднее время выхода новой стационарной консоли у двух крупных производителей PlayStation и Microsoft составляет 6.3 года и 6.5 лет соответственно. Среднее значение продолжительности существования платформы составляет 8.5 лет, медианное - 9,5 лет (рассчитано ранее было)

В результате исследования предыдущих вопросов можно выделить актуальный период: с 2013г по 2016г. По следующим двум причинам:

  1. Начиная с 2013г, каждый год выпускается приблизительно равное количество игр.
  2. Падение на данном временом отрезке суммарных продаж игр на популярных ранее платформах ('PS3', 'X360', 'Wii') говорит о том, что появляются новые игровые платформы, которые набирают популярность.
In [56]:
#возьмем соответствующий срез
#Еще удалим данные по платформе DS потому что после 2013г игры на ней не продавались (см. выше график)

data_relevant = data.query('year_of_release >= 2013  and platform != "DS"').reset_index(drop=True)

print(len(data_relevant))
data_relevant.sample(5)
2229
Out[56]:
name platform year_of_release genre na_sales eu_sales jp_sales other_sales critic_score user_score rating all_sales
1113 Samurai Warriors 4-II PS3 2015 Action 0.00 0.00 0.11 0.00 NaN NaN T 0.11
835 Sniper: Ghost Warrior 2 X360 2013 Shooter 0.06 0.12 0.00 0.02 52.0 5.7 M 0.20
2204 Rugby Challenge 3 XOne 2016 Sports 0.00 0.01 0.00 0.00 NaN 6.6 E 0.01
2071 Raven's Cry PS4 2015 Role-Playing 0.00 0.01 0.00 0.00 NaN NaN unknow 0.01
1986 TV Anime Idolm@ster: Cinderella Girls G4U! Pac... PS3 2015 Action 0.00 0.00 0.02 0.00 NaN NaN unknow 0.02
In [57]:
data_relevant.query('platform == "PSP"')['year_of_release'].value_counts()
Out[57]:
2013    55
2014    10
2015     3
Name: year_of_release, dtype: int64

На платформе PSP продажи прекратились в 2015году. Поэтому также исключим данную платформу из рассмотрения.

In [58]:
data_relevant = data_relevant.query('platform != "PSP"')

print(len(data_relevant))
data_relevant.sample(5)
2161
Out[58]:
name platform year_of_release genre na_sales eu_sales jp_sales other_sales critic_score user_score rating all_sales
1538 Resident Evil 4 HD PS4 2016 Shooter 0.04 0.00 0.00 0.01 NaN NaN unknow 0.05
1300 Dragon's Dogma Online PS4 2015 Role-Playing 0.00 0.00 0.08 0.00 NaN NaN unknow 0.08
669 Lego Batman 3: Beyond Gotham PSV 2014 Action 0.05 0.19 0.00 0.07 NaN 7.7 E10+ 0.31
1805 Loading Human PS4 2016 Adventure 0.01 0.01 0.00 0.00 NaN NaN unknow 0.02
728 Project CARS XOne 2015 Racing 0.11 0.13 0.00 0.02 81.0 5.8 E 0.26
In [59]:
#посмотрим какие у нас вообще есть платформы на выбранном отрезке времени
data_relevant['platform'].unique()
Out[59]:
array(['PS3', 'X360', 'PS4', '3DS', 'XOne', 'WiiU', 'Wii', 'PC', 'PSV'],
      dtype=object)
In [60]:
#Получаем 9 основных платформ.
display(data_relevant['platform'].value_counts())
PS4     392
PSV     358
PS3     345
3DS     303
XOne    247
PC      192
X360    186
WiiU    115
Wii      23
Name: platform, dtype: int64
In [61]:
#по количеству проданых игр есть лидеры посмотри, что по продажам

#сделаем шрифт крупнее
matplotlib.rcParams.update({'font.size': 12})


fig, ax = plt.subplots(nrows = 3, ncols = 3, figsize=(16, 20))

i=0
for name, group_data in data_relevant.groupby('platform'):

    ax_cycle = ax[int((i)/3)][(i)%3]
        
    data_relevant_name_platform = group_data.pivot_table(index='year_of_release', values='all_sales', aggfunc='sum')
    data_relevant_name_platform['year'] = data_relevant_name_platform.index
    #display(data_relevant_name_platform)
    
    data_relevant_name_platform.plot(x='year', y='all_sales', xlim=(2013, 2016), marker='o', linewidth=2, markersize=12,\
                        title = name+'\n Общее кол-во проданных игр: '+str(data_relevant['platform'].value_counts()[name]),\
                        grid = True, label='Суммарные продажи', ax=ax_cycle)
    
    #цена деления основной оси Х
    ax_cycle.xaxis.set_major_locator(ticker.MultipleLocator(1))
    #цена деления вспомогательной оси Y
    ax_cycle.yaxis.set_minor_locator(ticker.MultipleLocator(4))
    
    #  Включаем видимость вспомогательных делений:
    ax_cycle.minorticks_on()
    #задаваем внешний вид вспомогательной сетки
    ax_cycle.grid(which='minor', color = 'gray', linestyle = ':')
    
    ax_cycle.set_xlabel('Год')
    ax_cycle.set_ylabel('МЛН, $')
    i += 1

fig.tight_layout()
plt.show()

Вывод

Из анализа представленных выше графиков следует, что к 2016 году суммарные продажи упали у всех платформ. Наиболее успешными были PS4 и XOne, т.к. продажи по ним расли с 2013 по 2015 года.
За границу определяющую потенциально прибыльные платформы будем считать суммарные продажи на PC в 2016 году (чуть больше 5 млн.$). Т.е. платформы, у которых суммарныепродажи в 2016г выше 5млн. будем считать потенциально прибыльными, включая платформу PC (т.к. игры для пк никогда не переставали выходить). Таким образом, к потенциально прибыльным платформам можно отнести следующие: PS4, XOne, 3DS и PC.

Построим интерактивный график для удобства анализа и наглядности. Отметим на нем пунктиром среднее и увеличим масштаб по оси OY (рассмотрим значение от 0 до 2.16 млн.$)

In [62]:
trace = []
for name in data_relevant['platform'].unique():
    trace.append(
        go.Box(
            y=data_relevant[data_relevant['platform']==name]['all_sales'], 
            name=name,
            boxmean=True
        )
    )

# визуализируем данные
fig = go.Figure(data=trace,layout ={'title': '«Ящик с усами» по глобальным продажам каждой игры с разбивкой по платформам',\
                                         'xaxis_title' : 'Платформы',
                                         'yaxis_title' : 'млн. $'
                                   })
#вначале увеличим область
fig.update_yaxes(range=(0.0, 2.02))
fig.show()

#выведем количественные значения медиан и средних
platform_med_mean = data_relevant.pivot_table(index='platform', values='all_sales', aggfunc=['median', 'mean'])
platform_med_mean.columns = ['median', 'mean']
#транспонируем
platform_med_mean = platform_med_mean.T
display(platform_med_mean)
platform 3DS PC PS3 PS4 PSV Wii WiiU X360 XOne
median 0.090000 0.080000 0.150000 0.200000 0.040000 0.180000 0.200 0.265000 0.22000
mean 0.472772 0.208646 0.525884 0.801378 0.092151 0.593913 0.562 0.735484 0.64502

Наличие выбросов на графике скорее всего обусловлены выходом очень популярных у пользователей игр на платформах. Если это так, то удалять их будет неправильно, т.к. компании обычно презентуют дату выхода игры и получается, что наши выбросы не совсем случайны и продавец игр может это использовать.

In [63]:
#Посмотрим выбросы на платформе Xbox one
data_relevant.query('platform == "XOne" and all_sales > 2').sort_values(by="all_sales", ascending=False).head(10)
Out[63]:
name platform year_of_release genre na_sales eu_sales jp_sales other_sales critic_score user_score rating all_sales
14 Call of Duty: Black Ops 3 XOne 2015 Shooter 4.59 2.11 0.01 0.68 NaN NaN unknow 7.39
22 Grand Theft Auto V XOne 2014 Action 2.81 2.19 0.00 0.47 97.0 7.9 M 5.47
24 Call of Duty: Advanced Warfare XOne 2014 Shooter 3.22 1.55 0.01 0.48 81.0 5.4 M 5.26
31 Halo 5: Guardians XOne 2015 Shooter 2.78 1.27 0.03 0.41 84.0 6.4 T 4.49
39 Fallout 4 XOne 2015 Role-Playing 2.51 1.32 0.01 0.38 88.0 6.2 M 4.22
52 Star Wars Battlefront (2015) XOne 2015 Shooter 2.04 1.28 0.02 0.32 NaN NaN unknow 3.66
55 Assassin's Creed: Unity XOne 2014 Action 2.27 0.90 0.00 0.33 72.0 4.1 M 3.50
61 Destiny XOne 2014 Shooter 2.14 0.92 0.00 0.31 75.0 5.5 T 3.37
65 Gears of War: Ultimate Edition XOne 2015 Shooter 2.61 0.33 0.00 0.34 82.0 7.5 M 3.28
66 FIFA 16 XOne 2015 Sports 0.89 2.12 0.00 0.24 84.0 4.4 E 3.25

Действительно все эти игры очень популярны (даже люди далекие от игр скорее всего слышали о каких-то) и о дате релиза компании говорили заранее, поэтому продавец магазина игр может использовать эту информацию для повышения продаж. (как бы получается, что эти выбросы могут быть "прогнозируемыми", в начальный период прадажи резко возрастут, потому что, чтобы разочароваться в игре вначале надо ее купить)

Вывод

Если рассматривать медианные значения, то все плотформы можно условно разбить на три категории: первая - платформы с медианной суммой продаж меньше 100 тыс.д. (3DS, PC, PSV), данная категория характеризуется малым межквартильным разбросом, вторая - с медианной суммой продаж от 100 до 200 тыс.д.(PS3, Wii), данная категория характеризуется средним межквартильным разбросом и третья - с медианной суммой продаж больше 100 тыс.д. (PS4, WiiU, X360, XOne), эта категория характеризуется большим межквартильным разбросом по сравнению с другими категориями. Минимальная и максимальная разница медианных продаж внутри первой категории составляет 10 и 50 тыс соответственно, внутри второй - 30 тыс. и внутри третьей - 20 и 65 тыс.

Средние значения существенно выше медианных, наши данные скошены влево. С точки зрения продавца игр и получения максимальной выгоды интересны как раз среднее (если следовать нашему предположению, что выбросы это популярные игры о дате релиза которых можно узнать заранее). Поэтому если рассматривать среднее значение, то самой непопулярной платформой будет являться PSV со средними суммарными продажами в 92 тыс. Остальные платформы более успешные у них средние суммарные продажи лежат в диапазоне от 208 тыс.(PC) до 800 тыс.(PS4). И условно платформы можно разбить на 2 категории: первая со средними продажами в диапазоне от 208 до 600 тыс. (PC, 3DS, PS3, Wii, WiiU), вторая - в диапазоне от 650 до 800 тыс. (XOne, X360, PS4).

Если рассматривать медианные продажи, то там была выделена группа суммой продаж меньше 100 тыс.д., куда вошли 3DS и PSV - такие низкие значения можно объяснить тем, что это портативные платформы и стоимость игр для них ниже, чем для стационарных. В эту, первую группу также входи и РС - это вхождение можно попытаться объяснить высоким пиратством для компьютерных игр. Разницу между второй и третьей категорией объясняется тем, что во второй категории находятся устаревающие платформы 7-го поколения, в то время как в третьей категории находятся новые платформы 8-го поколения, кроме X360. Видимо данная платформа находится в последней категории, потому что она стала весьма популярной у пользователей.

Рассмотрм, для примера, платформу PS4

In [64]:
#функция, которая по названию платформы строит диаграммы рассеяния для суммарных продаж от отзывов критиков и пользователей
def user_critic_scatter(name_platform):
    try:
        data_relevant_for_platform = data_relevant.query('platform == @name_platform').reset_index(drop=True)
        print('Всего записей для платформы '+name_platform+': ', len(data_relevant_for_platform))
        
        #сформируем два датафрейма для пользователей и критиков
        data_user = data_relevant_for_platform[['user_score', 'all_sales']].reset_index(drop=True)
        print('Количество записей об оценках пользователей: ', len(data_user))
        
        data_critic = data_relevant_for_platform[['critic_score', 'all_sales']].reset_index(drop=True)
        print('Количество записей об оценках критиков: ', len(data_critic))
        
        #для каждого вычисляем коэффициент корреляции и строим диаграмму рассеяния
        fig, ax = plt.subplots(nrows = 1, ncols = 2,  figsize=(12,5))

        coeff = round(data_user['user_score'].corr(data_user['all_sales']), 2)
        data_user.plot(x='user_score', y='all_sales', kind='scatter', ax=ax[0], grid=True,
                   title='Коэффициент корреляции: '+str(coeff)+'\n')

        coeff = round(data_critic['critic_score'].corr(data_critic['all_sales']), 2)
        data_critic.plot(x='critic_score', y='all_sales', kind='scatter', ax=ax[1], grid=True,
                     title='Коэффициент корреляции: '+str(coeff)+'\n')

#data_relevant_name_platform.plot(x='year', y='all_sales', xlim=(2013, 2016), marker='o', linewidth=2, markersize=12,\
#                        title = name+'\n Общее кол-во проданных игр: '+str(data_relevant['platform'].value_counts()[name]),\
#                        grid = True, label='Суммарные продажи', ax=ax_cycle)
    
        ax[0].set_xlabel('Оценки пользователей')
        ax[0].set_ylabel('МЛН, $')
        ax[1].set_ylabel('МЛН, $')
        ax[1].set_xlabel('Оценки критиков')

        fig.suptitle('Платформа: '+name_platform)
        fig.tight_layout(pad=3)
        plt.show()
        
    except:
        print('ERROR in user_critic_scatter!!!\n')
        
#user_critic_scatter('PS4')
In [65]:
user_critic_scatter('PS4')
Всего записей для платформы PS4:  392
Количество записей об оценках пользователей:  392
Количество записей об оценках критиков:  392

Вывод

Оценки пользователей практически не влияют на суммарные продажи. Другая ситуация для критиков. Наблюдается прямая корреляция между суммарными продажами и оценками критиков (чем выше оценка, тем выше суммарные продажи). Скорее всего это связано с тем, что критики обычно оценивают игру перед выходом, в то время как пользователе уже после ее покупки и оценки геймплея.

Рассмотрим другие платформы

In [66]:
user_critic_scatter('Wii')
Всего записей для платформы Wii:  23
Количество записей об оценках пользователей:  23
Количество записей об оценках критиков:  23

Для данной платформы мало записей, чтобы делать точные выводы.

In [67]:
for name in data_relevant['platform'].unique():
    if (name != "PS4") & (name != "Wii"):
        user_critic_scatter(name)
Всего записей для платформы PS3:  345
Количество записей об оценках пользователей:  345
Количество записей об оценках критиков:  345
Всего записей для платформы X360:  186
Количество записей об оценках пользователей:  186
Количество записей об оценках критиков:  186
Всего записей для платформы 3DS:  303
Количество записей об оценках пользователей:  303
Количество записей об оценках критиков:  303
Всего записей для платформы XOne:  247
Количество записей об оценках пользователей:  247
Количество записей об оценках критиков:  247
Всего записей для платформы WiiU:  115
Количество записей об оценках пользователей:  115
Количество записей об оценках критиков:  115
Всего записей для платформы PC:  192
Количество записей об оценках пользователей:  192
Количество записей об оценках критиков:  192
Всего записей для платформы PSV:  358
Количество записей об оценках пользователей:  358
Количество записей об оценках критиков:  358

Вывод

Выводы для PS4 справедлив для всех остальных платформ, кроме платформ WiiU и 3DS. Так как для этих двух платформ, помимо того, что наблюдается прямая корреляция между отзывами критиков и суммарными продажами, также наблюдается прямая корреляция между отзывами пользователей и продажами.

3DS и WiiU - это платформы, выпускаемые японской компанией Nintendo. Возможно, что у компании сильно развита политика бетатестирования, где пользователи могут оценить геймплей до официальных продаж и выставить оценку. Тем более, согласно википедии, у WiiU был сложный контроллер и надо было оценить как он понравится людям на разных играх.

In [68]:
data_relevant['genre'].unique()
Out[68]:
array(['Action', 'Shooter', 'Role-Playing', 'Misc', 'Sports', 'Fighting',
       'Racing', 'Simulation', 'Platform', 'Strategy', 'Adventure',
       'Puzzle'], dtype=object)

Игры за рассматриваемый период представлены 12 жанрами. Посмотрим каких жанров игр было больше всего.

In [69]:
data_relevant['genre'].value_counts()
Out[69]:
Action          755
Role-Playing    285
Adventure       211
Sports          208
Shooter         187
Misc            146
Racing           85
Fighting         79
Platform         72
Simulation       61
Strategy         55
Puzzle           17
Name: genre, dtype: int64

Наиболее популярный выпускаемый жанром игр является - Action, менее популярным - жанр Puzzle. Посмотрим как жанр влияет на суммарные продажи

In [70]:
#Для выбора жанров с высокими и низкими продажами: 
#1. построим круговую диаграмму для суммарных продаж по жанрам
#2. построим «Ящик с усами» по глобальным продажам каждой игры с разбивкой по жанрам

from plotly.subplots import make_subplots

fig = make_subplots(rows=1, 
                    cols=2,
                    column_widths=[0.4, 0.55], #row_heights
                    specs=[[{"type": "domain"}, {"type": "xy"}]],
                    subplot_titles=("Суммарные продажи игр",
                                    "«Ящик с усами» по глобальным продажам каждой игры\n"
                                   )
)


#Вычислим суммарные продажи по жанрам.
data_genre_sales = data_relevant.pivot_table(index='genre', values='all_sales', aggfunc='sum')
data_genre_sales=data_genre_sales.sort_values(by='all_sales', ascending=False)
#display(data_genre_sales)

fig.add_trace(go.Pie(labels=data_genre_sales['all_sales'].index, values=data_genre_sales['all_sales'], hole=0.25), 
              row=1, col=1
             )

#построим «Ящик с усами» по глобальным продажам каждой игры с разбивкой по жанрам
for name in data_relevant['genre'].unique():
    
    fig.add_trace(
        go.Box(
            y=data_relevant[data_relevant['genre']==name]['all_sales'], 
            name=name,
            boxmean=True,
            showlegend=False
              ),
        row=1,
        col=2
    )

fig.update_yaxes(range=(0.0, 3.5), title='млн. $') 

fig.update_layout(
    title_text="Данные с разбивкой по жанрам за период с 2013 по 2016гг.",
    height=420,
    width=950,
)

fig.show()

#выведем количественные значения медиан и средних
print('Количественные значения медиан и средних для "ящика с усами"')
genre_med_mean = data_relevant.pivot_table(index='genre', values='all_sales', aggfunc=['median', 'mean'])
genre_med_mean.columns = ['median', 'mean']
#транспонируем
genre_med_mean = genre_med_mean.T
display(genre_med_mean)
Количественные значения медиан и средних для "ящика с усами"
genre Action Adventure Fighting Misc Platform Puzzle Racing Role-Playing Shooter Simulation Sports Strategy
median 0.110000 0.030000 0.130000 0.115000 0.2250 0.060000 0.120000 0.120000 0.450000 0.100000 0.250000 0.080000
mean 0.425351 0.108531 0.446709 0.428562 0.5825 0.186471 0.469294 0.508281 1.245882 0.353279 0.720817 0.182909

Вывод

С точки зрения суммарных продаж, больше всего дохода приносят Action, Shooter, Sports, Role-Playing. Однако, игр с жанром Action выпускают ~2.5 раза больше, чем другие жанры. Поэтому стоит рассмотреть другой график с boxplot'ами по глобальным продажам игр. Из него следует, что жанром с самыми высокими продажами является - Shooter, на втором и третьем месте после него идут жанры Sports и Platform. Жанрами с низкимим продажами являются - Adventure, Puzzle и Strategy.

4. Составим портрет пользователя каждого региона.

In [71]:
data_relevant.head()
Out[71]:
name platform year_of_release genre na_sales eu_sales jp_sales other_sales critic_score user_score rating all_sales
0 Grand Theft Auto V PS3 2013 Action 7.02 9.09 0.98 3.96 97.0 8.2 M 21.05
1 Grand Theft Auto V X360 2013 Action 9.66 5.14 0.06 1.41 97.0 8.1 M 16.27
2 Call of Duty: Black Ops 3 PS4 2015 Shooter 6.03 5.86 0.36 2.38 NaN NaN unknow 14.63
3 Pokemon X/Pokemon Y 3DS 2013 Role-Playing 5.28 4.19 4.35 0.78 NaN NaN unknow 14.60
4 Grand Theft Auto V PS4 2014 Action 3.96 6.31 0.38 1.97 97.0 8.3 M 12.62
In [72]:
data_platform_region = data_relevant.pivot_table(index='platform',
                                                 values=['na_sales', 'eu_sales', 'jp_sales'],
                                                 aggfunc = 'sum'
                                                )

data_platform_region
Out[72]:
eu_sales jp_sales na_sales
platform
3DS 30.96 67.81 38.20
PC 25.84 0.00 11.19
PS3 67.81 23.35 63.50
PS4 141.09 15.96 108.74
PSV 6.10 18.59 5.04
Wii 5.93 0.05 6.56
WiiU 19.85 10.88 29.21
X360 42.52 0.51 81.66
XOne 51.59 0.34 93.12
In [73]:
#бросается в глаза, что платформа 'PC' в Японии такая не популярная.
#Ради интереса найдем игры вообще за все времена, когда были не нулевые продажи там
data.query('platform == "PC" and jp_sales > 0.0')
#Возвращаемся к заданию
Out[73]:
name platform year_of_release genre na_sales eu_sales jp_sales other_sales critic_score user_score rating all_sales
284 Half-Life PC 1997 Shooter 4.03 0.00 0.09 0.0 96.0 9.1 M 4.12
665 Half-Life 2 PC 2004 Shooter 2.28 0.02 0.08 0.0 96.0 9.1 M 2.38

Определим для пользователя каждого региона (NA, EU, JP) топ-5.

In [74]:
data_platform_top_NA = data_platform_region['na_sales'].sort_values(ascending=False).head()
data_platform_top_EU = data_platform_region['eu_sales'].sort_values(ascending=False).head()
data_platform_top_JP = data_platform_region['jp_sales'].sort_values(ascending=False).head()

#Для рассмотрения долей продаж удобно строить круговые диаграмы
fig = make_subplots(rows=1, 
                    cols=3,
                    column_widths=[0.33, 0.33, 0.34], #row_heights
                    specs=[[{"type": "domain"}, {"type": "domain"}, {"type": "domain"}]],
                    subplot_titles=("Северная Америка", "Европа", "Япония")
)

fig.add_trace(go.Pie(labels=data_platform_top_NA.index, values=data_platform_top_NA.values, hole=0.25), 
              row=1, col=1
             )
fig.add_trace(go.Pie(labels=data_platform_top_EU.index, values=data_platform_top_EU.values, hole=0.25), 
              row=1, col=2
             )
fig.add_trace(go.Pie(labels=data_platform_top_JP.index, values=data_platform_top_JP.values, hole=0.25), 
              row=1, col=3
             )

fig.update_layout(
    title_text="Доли продаж игр на самых популярных платформах по регионам за период с 2013 по 2016гг.",
    height=420,
    width=950,
)

fig.show()

Вывод

Самой популярной платформой в Европе и Северной Америке является PS4, причем в Европе болле популярна. В Японии же самой популярной является 3DS, котроря в двух оставшихся регионах занимает последнее место в топ 5.

По сути весь топ 5 в 3-х регионах поделен в основном между тремя линейками плейстейшен (PS4, PS3, PSV), майкрософт (Xone, X360) и нинтендо (3DS). Если рассматривать с такой точки зрения, то в Северной Америке приблизительно одинаково популярны линейки плейстейшен и майкрософт, в Европе предпочитают больше плейстейшен, а в Японии - линейка игр на платформе плейстейшен и нинтендо, причем здесь в топ-5 вообще нет представителей майкросовт.

Дальше посмотрим как менялись доли продаж по платформам по годам.

У японскго рынка выделяются два отличия:
1) В Японии предпочитают играть не на стационарных платформах, а на портативных.
2) Топ рынка игровых платформ занимают японские производители

In [75]:
#для дальнейшего быстрого построения круговых диаграмм напишем функцию
def pie_part_region(data_na, data_eu, data_jp, title):
    try:
        fig = make_subplots(rows=1, 
                    cols=3,
                    column_widths=[0.33, 0.33, 0.34], #row_heights
                    specs=[[{"type": "domain"}, {"type": "domain"}, {"type": "domain"}]],
                    subplot_titles=("Северная Америка", "Европа", "Япония")
        )

        fig.add_trace(go.Pie(labels=data_na.index, values=data_na.values, hole=0.25), 
                      row=1, col=1
                     )
        fig.add_trace(go.Pie(labels=data_eu.index, values=data_eu.values, hole=0.25), 
                      row=1, col=2
                     )
        fig.add_trace(go.Pie(labels=data_jp.index, values=data_jp.values, hole=0.25), 
                      row=1, col=3
                     )

        fig.update_layout(title_text=title, height=400, width=950)

        fig.show()
    except:
        print('ERROR in pie_part_region!!!')
        
#test
#pie_part_region(data_platform_top_NA, data_platform_top_EU, data_platform_top_JP, 'test')
In [76]:
data_genre_region = data_relevant.pivot_table(index='genre',
                                                 values=['na_sales', 'eu_sales', 'jp_sales'],
                                                 aggfunc = 'sum'
                                                )

data_genre_top_NA = data_genre_region['na_sales'].sort_values(ascending=False).head()
data_genre_top_EU = data_genre_region['eu_sales'].sort_values(ascending=False).head()
data_genre_top_JP = data_genre_region['jp_sales'].sort_values(ascending=False).head()

#Для рассмотрения долей продаж удобно строить круговые диаграмы
text="Доли продаж игр по самых популярным жанрам по регионам за период с 2013 по 2016гг."
pie_part_region(data_genre_top_NA, data_genre_top_EU, data_genre_top_JP, text)

Вывод

В Северной Америке и Европе в топ-4 входят одинаковые жанры: 1 место - Action c 33.6% и 36.6% соответствено, 2 место - Shooter c 29.3% и 27.1% соответствено, 3 место - Sports c 17.4% и 18.6% и 4 место - Role-Playing c 12.4% и 11.4%. Жанр на 5-м месте для двух рассматриваемых регионов отличается в Европе предпочитают Racing, а в Северной Америке нестандартные жанры под общим названием Misc.

Иначе делло обстоит в Японии, у них топ-5 следующий: 1-место занимает жанр Role-Playing (44.3%), 2-место - Action (35.1%), 3-место - Misc (8%), 4-место - Fighting (6.76%) и 5 место занимает жанр Shooter (5.85%).

Стоит отметить, что жанр Action занимает приблизительно равную долю во всех регионах (в топ-5): 33.6-36.6%.

In [77]:
#Посмотрим какие рейтинги присутствуют вообще за рассматриваемый период
display(data_relevant['rating'].value_counts())

#исключим из рассмотрения записи с неизвестным рейтингом
data_relevant_rating = data_relevant.query('rating != "unknow"')

print(len(data_relevant))
print(len(data_relevant_rating))
unknow    789
M         423
T         373
E         312
E10+      264
Name: rating, dtype: int64
2161
1372

Имеем, что за период с 2013 по 2016гг. у игр, если указано, то было 4 основных рейтинга от ESRB.

In [78]:
#построим столбчатую диаграмму для начала подготовим данные

group_rating=data_relevant_rating.pivot_table(index='rating', values=['na_sales', 'eu_sales', 'jp_sales'], aggfunc='sum')
display(group_rating)

#Для более точного понимания данных составим словарь для рейтинга ESRB, согласно википедии

dict_ESRB ={'E' : 'Для всех (E)',
             'E10+' : 'Для всех от 10+ (E10+)',
             'M' : 'Для взрослых, 17+ (M)',
             'T' : 'Для подростков, 13+ (T)'
           }

group_rating=group_rating.set_index(pd.Series(data=dict_ESRB, index=dict_ESRB.keys()))
display(group_rating)
eu_sales jp_sales na_sales
rating
E 84.93 15.84 81.60
E10+ 45.04 6.27 56.16
M 157.15 14.87 175.18
T 43.68 22.46 51.98
eu_sales jp_sales na_sales
Для всех (E) 84.93 15.84 81.60
Для всех от 10+ (E10+) 45.04 6.27 56.16
Для взрослых, 17+ (M) 157.15 14.87 175.18
Для подростков, 13+ (T) 43.68 22.46 51.98
In [79]:
#Для рассмотрения долей продаж построим круговые диаграмы
text="Доли продаж в отдельном регионе в зависимости от рейтинга ESRB с 2013 по 2016гг."
pie_part_region(group_rating['na_sales'], group_rating['eu_sales'], group_rating['jp_sales'], text)

Вывод

В Европе и Северной Америке наибольший доход ~48% приносят игры с рейтингом M (17+). В Японии наибольший доход 37.8% приносят игры с рейтингом T (13+), который в других двух регионах приносит наименьший доход. Приблизительно четверть доходов в каждом регионе приносят игры с жанром для всех Е.

Вывод

В целом рынки Северной Америки и Европы похожи по популярным жанрам и платформам, также там одинаковое предпочтение игр по рейтингу ESRB. Особенностью японского рынка игр является, то что пользователи предпочитают портативные платформы стационарным, причем отечественного производства, любимым жанром игр - являются РПГ и Экшен, а наибольший доход приносят

5. Проверка гипотез.

1) Проверим, что средние пользовательские рейтинги платформ Xbox One и PC одинаковые.

In [80]:
#Подготовим две генеральные совокупности
#data_user_score_pc = data_relevant_user_score.query('platform == "PC"')
data_user_score_pc = data_relevant.query('platform == "PC"')
print(data_user_score_pc['user_score'].describe(),'\n')


#data_user_score_xone = data_relevant_user_score.query('platform == "XOne"')
data_user_score_xone = data_relevant.query('platform == "XOne"')
print(data_user_score_xone['user_score'].describe())
count    158.000000
mean       6.280380
std        1.735044
min        1.400000
25%        5.325000
50%        6.800000
75%        7.600000
max        9.300000
Name: user_score, dtype: float64 

count    182.000000
mean       6.521429
std        1.380941
min        1.600000
25%        5.800000
50%        6.800000
75%        7.500000
max        9.200000
Name: user_score, dtype: float64
In [81]:
warnings.filterwarnings("ignore")

#посмотрим на их гистограммы

ax = sns.distplot(data_user_score_pc[data_user_score_pc['user_score'].isna() == False]['user_score'], 
                                                      kde=True, norm_hist=True,
                                                      kde_kws={"color": "b", "lw": 2, "label": "PC"});

sns.distplot(data_user_score_xone[data_user_score_xone['user_score'].isna() == False]['user_score'], 
                                                     kde=True, norm_hist=True,
                                                     ax=ax, kde_kws={"color": "r", "lw": 2, "label": "Xbox One"});

#ax = sns.distplot(data_user_score_pc['user_score'], kde=True, norm_hist=True,\
#                                                      kde_kws={"color": "b", "lw": 2, "label": "PC"});
#
#sns.distplot(data_user_score_xone['user_score'], kde=True, norm_hist=True, ax=ax,\
#                                                      kde_kws={"color": "r", "lw": 2, "label": "Xbox One"});

ax.set_xlabel('Оценки пользователей')
ax.set_title('Распределение оценок пользователей для двух платформ\n', loc='center')

plt.show()

Провериv, что средние пользовательские рейтинги платформ Xbox One и PC одинаковые.

Сформулируем гипотезы

Нулевая гипотеза $H_0$: Средние пользовательские рейтинги платформ «Xbox One» и «PC» равны друг другу;

Альтернативная $H_1$: Средние пользовательские рейтинги платформ «Xbox One» и «PC» не равны друг другуу.

Чтобы проверить гипотезу о равенстве средних двух генеральных совокупностей по взятым из них выборкам, применим метод ttest_ind в качестве параметров метода передадим туда оценки пользователей для двух платформ. Кроме того, мы на гистограмме выше видем, что говорить о равенстве дисперсий трудно, поэтому также передадим методу параметр equal_var со значением False.

Зафиксируем уровень значимости $\alpha$ = 5%

In [82]:
#напишем функцию для проведения исследования
def ttest_rating(df_1, df_2, alpha):
    try:
        results = st.ttest_ind( df_1, df_2, equal_var = False)

        if (results.pvalue < alpha):
            print('pvalue= ',results.pvalue,':\t\tpvalue < alpha\t=>\tОтвергаем нулевую гипотезу')
        else:
            print('pvalue= ',results.pvalue,':\tpvalue > alpha\t=>\tНе получилось отвергнуть нулевую гипотезу')
    except:
        print("ERROR in ttest_rating")
In [83]:
alpha = 0.05

ttest_rating(data_user_score_xone['user_score'].dropna(), data_user_score_pc['user_score'].dropna(), alpha)
pvalue=  0.16174359801784308 :	pvalue > alpha	=>	Не получилось отвергнуть нулевую гипотезу

Вывод

Мы получили, что нулевая гипотеза о равенстве средних пользовательских рейтингов платформ «Xbox One» и «PC» не отвергается при заданом уровне значимости в 5%

2) Проверим, что cредние пользовательские рейтинги жанров Action и Sports разные.

In [84]:
#Подготовим две генеральные совокупности
#data_user_score_action = data_relevant_user_score.query('genre == "Action"')
data_user_score_action = data_relevant.query('genre == "Action"')
print(data_user_score_action['user_score'].describe(),'\n')


#data_user_score_sports = data_relevant_user_score.query('genre == "Sports"')
data_user_score_sports = data_relevant.query('genre == "Sports"')
print(data_user_score_sports['user_score'].describe())
count    391.000000
mean       6.842711
std        1.326763
min        2.000000
25%        6.300000
50%        7.100000
75%        7.800000
max        9.100000
Name: user_score, dtype: float64 

count    159.000000
mean       5.249686
std        1.783038
min        0.200000
25%        4.100000
50%        5.500000
75%        6.500000
max        8.800000
Name: user_score, dtype: float64
In [85]:
#посмотрим на гистограммы
ax = sns.distplot(data_user_score_action[data_user_score_action['user_score'].isna() == False]['user_score'], 
                                                      kde=True, norm_hist=True,
                                                      kde_kws={"color": "b", "lw": 2, "label": "Action"});

sns.distplot(data_user_score_sports[data_user_score_sports['user_score'].isna() == False]['user_score'], 
                                                     kde=True, norm_hist=True,
                                                     ax=ax, kde_kws={"color": "r", "lw": 2, "label": "Sports"});

#ax = sns.distplot(data_user_score_action['user_score'], kde=True, norm_hist=True,\
#                                                      kde_kws={"color": "b", "lw": 2, "label": "Action"});

#sns.distplot(data_user_score_sports['user_score'], kde=True, norm_hist=True, ax=ax,\
#                                                      kde_kws={"color": "r", "lw": 2, "label": "Sports"});

ax.set_xlabel('Оценки пользователей')
ax.set_title('Распределение оценок пользователей для двух жанров\n', loc='center')

warnings.filterwarnings("ignore")
plt.show()

Провериv, что средние пользовательские рейтинги жанров Action и Sports разные.

Сформулируем гипотезы

Нулевая гипотеза $H_0$: Средние пользовательские рейтинги жанров «Action» и «Sports» равны друг другу;

Альтернативная $H_1$: Средние пользовательские рейтинги жанров «Action» и «Sports» не равны друг другу.

Чтобы проверить гипотезу о равенстве средних двух генеральных совокупностей по взятым из них выборкам, применим метод ttest_ind в качестве параметров метода передадим туда оценки пользователей для двух платформ. Кроме того, мы на гистограмме выше видем, что дисперсии явно различные у двух генеральных совокупностей, поэтому передадим методу параметр equal_var со значением False.

Зафиксируем уровень значимости $\alpha$ = 5%

In [86]:
alpha = 0.05

ttest_rating(data_user_score_action['user_score'].dropna(), data_user_score_sports['user_score'].dropna(), alpha)
pvalue=  2.3284403879742492e-20 :		pvalue < alpha	=>	Отвергаем нулевую гипотезу

Вывод

Мы получили, что нулевая гипотеза о равенстве средних пользовательских рейтингов жанров «Action» и «Sports» отвергается.

6. Общий вывод.

В ходе выполнения проекта был решен ряд задач:

  1. Проведена предобраподка данных. Мы привели названия столбцов к нижнему регистру, заполнили пропуски, привели данные к нужным типам и проверили данные на корректность. Для последующего анализа сделали преобразования над таблицей, добавив столбец с суммарными продажами.

  2. Был проведен исследовательский анализ данных На основе анализа времени существования игровых платформ и подсчета количества игр, выпускаемых ежегодно, был определен актуальный период (с 2013 по 2016 годы) для прогноза на 2017 год. По динамике продаж за актуальный период были выбраны потенциально прибыльные платформы: PS4, XOne, 3DS и PC

  3. Были построены графики по глобальным продажам игр с разбивкой по платформам, который позволил ответить на вопросы о средних и медианных разницах в продажах на разных платформах. Рассмотрев медианные значения продаж, тплотформы были условно разбить на три категории: первая - платформы с медианной суммой продаж меньше 100 тыс.д. (3DS, PC, PSV), данная категория характеризуется малым межквартильным разбросом, вторая - с медианной суммой продаж от 100 до 200 тыс.д.(PS3, Wii), данная категория характеризуется средним межквартильным разбросом и третья - с медианной суммой продаж больше 100 тыс.д. (PS4, WiiU, X360, XOne). Было показано, что наши данные скошены влево: средние значения существенно выше медианных. Поэтому если рассматривать среднее значение, то самой непопулярной платформой будет являться PSV со средними суммарными продажами в 92 тыс. Остальные платформы более успешные у них средние суммарные продажи лежат в диапазоне от 208 тыс.(PC) до 800 тыс.(PS4). И условно платформы можно разбить на 2 категории: первая со средними продажами в диапазоне от 208 до 600 тыс. (PC, 3DS, PS3, Wii, WiiU), вторая - в диапазоне от 650 до 800 тыс. (XOne, X360, PS4).

  4. Исследовано по платформам как отзывы пользователей и критиков на игры влияют на продажи. Для всех рассмотреных платформ, кроме платформ WiiU и 3DS, оценки пользователей практически не влияют на суммарные продажи. Другая ситуация для критиков. Наблюдается прямая корреляция между суммарными продажами и оценками критиков (чем выше оценка, тем выше суммарные продажи). Для платформ WiiU и 3DS кроме того, что наблюдается прямая корреляция между отзывами критиков и суммарными продажами, также наблюдается прямая корреляция между отзывами пользователей и продажами.

  5. Рассмотрены распределения игр по жанрам и выделены жанры с высокимим и низкими продажами. Жанром с самыми высокими продажами является - Shooter, на втором и третьем месте после него идут жанры Sports и Platform. Жанрами с низкимим продажами являются - Adventure, Puzzle и Strategy. Стоит отметить, что игры с жанром Action выпускают ~2.5 раза больше, чем другие жанры. И с точки зрения суммарных продаж, больше всего дохода приносят Action, Shooter, Sports, Role-Playing.

  6. Определены для пользователя каждого региона самые популярные платформы и жанры *Самой популярной платформой в Европе и Северной Америке является PS4, причем в Европе болле популярна. В Японии же самой популярной является 3DS, котроря в двух оставшихся регионах занимает последнее место в топ 5. К 2016 году платформа PS4 нарастила свое влияние во всех трех регионах. В Японии традиционно лидирует 3DS. В 2016 году доля XOne по регионам в топ-5: Северная Америка - 32.9%, Европа - 19.8%, Япония - 0%. Также приобретает популярность PC с 2014 в Европе, а с 2016 появляется в топе на последней позиции и в Северной Америке. В Японии данная платформа отсутствует в топе во всех рассматриваемых периодах.

  7. Было проанализировано влияние рейтинга ESRB на продажи в регионах. Где показано, что в Европе и Северной Америке наибольший доход ~48% приносят игры с рейтингом M (17+). В Японии наибольший доход 37.8% приносят игры с рейтингом T (13+), который в других двух регионах приносит наименьший доход. Приблизительно четверть доходов в каждом регионе приносят игры с жанром для всех - Е.

  8. Были проверены две гипотезы. Первая гипотеза о том, что средние пользовательские рейтинги платформ Xbox One и PC одинаковые. Вторая - cредние пользовательские рейтинги жанров Action и Sports разные. Применив для проверки статистичексий критерий, обе гипотезы были приняты. Выводы также были подтверждены соответствующими гистограммами.